package com.ctepl.common.db;

import java.sql.*;
import java.io.*;
import java.util.*;

import org.apache.log4j.Logger;


/**
 * ConnectionFactory is a singleton class for all of Syrrx's database connection
 * pooling requirements.
 * It uses bitmechanic's connection pooling implementaion and API's.
 *
 * Usage:
 *    1. Create a file default.txt in a folder,  ./db  on the web server.
 *       This is the defination file where all the alias names and
 *       the connection parameter files associated with these aliases are defined.
 *       Eg. A typical default.txt file will contain:-
 *
 *           structdb	/db/structdb.dat
 *           chem1	/db/chem1.dat
 *
 *       structdb --> alias name
 *       /db/structdb.dat --> File path having the connection parameters values.
 *
 *       (Note: This Example assumes Unix-based file notation, for Windows the path would be:
 *        C:\\db\\structdb.dat)
 *
 *     2. Insure that all the parameter files defined above exhist.
 *        Eg. A typical conn-param file should contain the following entries:
 *
 *             alias         chem1
 *             dbURL         jdbc:oracle:thin:@sunserver01:1521:chem1
 *                           #jdbc:oracle:thin@hostname:port:SID
 *             dbDriver      oracle.jdbc.driver.OracleDriver
 *             dbUser        username
 *             dbPassword    password
 *             minConns      0
 *             maxConns      6
 *
 *      3. All the above files should have a read permission.
 *
 * Example Code:
 *        try{
 *              Connection conn = ConnectionFactory.getConnection("MyAlias");
 *        }catch(SQLException s){
 *              s.printStackTrace();
 *        }
 */
 public class ConnectionFactory {
    static Logger log = Logger.getLogger(ConnectionFactory.class.getName());
    protected static boolean isInitialized = false;   
    protected static Properties definedConnections = new Properties();
    protected static Hashtable connInfo = new Hashtable();

    public static String DEFINED_CONNECTIONS_FILE = "default.txt" ;

    // cannot instantiate ConnectionFactory(), all methods are defined static.
    protected ConnectionFactory() { }

    /**
     * Test harness
     * @param arg - not used.
     */
    public static void main(String []arg ){
     //   init();
        
    }

    /**
     * Load the master pool definition file and the associated
     * *.dat files into a master Hashtable.
     * Initializes the following variables:
     *     * connNames -- all connection alias names
     *     * definedConnections -- mapping of alias to *.dat file
     *     * connInfo -- mapping of alias to Properties from *.dat file.
     * @param poolFileName -- the file that defines all pools, usu. "default.txt"
     */
    protected static void loadPools(String poolFileName) throws FileNotFoundException, IOException {
        definedConnections.load(new FileInputStream(poolFileName));
        Enumeration connNames = definedConnections.propertyNames();
        String aliasName;
        while(connNames.hasMoreElements()) {
            aliasName = (String)connNames.nextElement();
            String connFile = (String)definedConnections.get(aliasName);
            Properties p = new Properties();
            p.load(new FileInputStream(connFile));
            connInfo.put(aliasName, p);
        }
    }

    protected static void forceCreatePool(String aliasName)
                                throws SQLException, IllegalAccessException,
                                       InstantiationException, ClassNotFoundException {
        Properties p = (Properties)connInfo.get(aliasName);
        String dbDriver = (String) p.get("dbDriver");
        String dbURL = (String) p.get("dbURL");
        String dbUser  = (String) p.get("dbUser");
        String dbPassword = (String) p.get("dbPassword");
        int minConns   = Integer.parseInt((String) p.get("minConns")); // min conns to open at startup
        int maxConns   = Integer.parseInt((String) p.get("maxConns")); // max conns to be opened at any time        
    }

    protected static void createPools() throws SQLException, IllegalAccessException,
                                                InstantiationException, ClassNotFoundException {
        Enumeration connNames = connInfo.keys();
        while(connNames.hasMoreElements()) {
            forceCreatePool((String)connNames.nextElement());
        }
    }

    /**
     * Get the Properties (user, pass, etc) for a given alias
     * @param aliasName -- the alias to return Properties for
     * @return the Properties (dbDriver, dbURL, dbUser, dbPassword, minConns, maxConns)
     */
    public static Properties getConnProperties(String aliasName) {
        return(Properties)connInfo.get(aliasName);
    }

    /*protected static void init() {

        // only initialize once
        if (isInitialized) return;
        String dbfile = System.getProperty("dbfile");
        if  (dbfile!= null && dbfile.length() > 2) {
            DEFINED_CONNECTIONS_FILE = dbfile;
        }

        try{
		    mgr = new ConnectionPoolManager(4000);
            loadPools(DEFINED_CONNECTIONS_FILE);
            createPools();
        } catch(SQLException s) {
              System.err.println("SQLException in ConnectionFactory.init():");
              s.printStackTrace();
        } catch(FileNotFoundException f) {
              System.err.println("FileNotFoundException in ConnectionFactory.init():");
              f.printStackTrace();
        } catch(IOException io) {
              System.err.println("IOException in ConnectionFactory.init():");
              io.printStackTrace();
        } catch(IllegalAccessException ia) {
              System.err.println("IllegalAccessException in ConnectionFactory.init():");
              ia.printStackTrace();
        } catch(Exception e) {
              System.err.println("Runtime Exception in ConnectionFactory.init():");
              e.printStackTrace();
        }

        isInitialized = true;
    }// end init()
*/

    protected static synchronized void createPool(String aliasName){

        // if the pool exists, then just return
        
        Properties p = new Properties();
        try{
            File paramFile = new File(DEFINED_CONNECTIONS_FILE);
            definedConnections.load(new FileInputStream(paramFile));

            String connFile = (String)definedConnections.get(aliasName);
            p.load(new FileInputStream(connFile));
            String dbDriver = (String) p.get("dbDriver");
            String dbURL = (String) p.get("dbURL");
            String dbUser  = (String) p.get("dbUser");
            String dbPassword = (String) p.get("dbPassword");
            //int minConns   = Integer.parseInt((String) p.get("minConns")); // min conns to open at startup
            int maxConns   = Integer.parseInt((String) p.get("maxConns")); // max conns to be opened at any time            
		
        }catch(FileNotFoundException f){
            log.error("FileNotFoundException in ConnectionFactory.createPool():"+f.getMessage(),f);
           
        }catch(IOException io){
        	log.error("IOException in ConnectionFactory.createPool():"+io.getMessage(),io);
       
        }catch(Exception e){
        	log.error("Runtime Exception in ConnectionFactory.createPool():"+e.getMessage(),e);
        
        }
    }

    


    /*
     * This method is for Syrrx projects XtalQuery,XtalTracker,PBreg and RaceRx.
     * The rest of the applications do not use this method
     * -charudath
     *
     */
    public static synchronized Connection getWLConnection(String alias) throws SQLException{      
		WLConnectionManager wlConMan = WLConnectionManager.getInstance(alias);
		try {
		    return wlConMan.getConnection();
		} catch(Exception e) {			
			return null;
		}
    }

    public static synchronized Connection getWLChemConnection(String dataSource) throws SQLException{
    	WLConnectionManager wlConMan = WLConnectionManager.getChemInstance(dataSource);
		try {
		    return wlConMan.getChemConnection();
		} catch(Exception e) {			
			return null;
		}
    }
    
    /**
    * A utility used to close a statement that was prevously used ignoring all exceptions.
    * Can be used to make the code more readable.
    *
    * @param ps1 an open Statement that needs closing (or null)
    */
    public static void closeStatement(Statement s1) {
        if (s1 != null) {
            try { s1.close(); } catch (Exception ignoreAll) {;}
        }
    }

    /**
    * Close an open connection, sets autocommit false and ignores all exceptions.
    * Can be used to make your code more readable.
    *
    * @param conn an open database connection (or null)
    */
    public static void closeConnection(Connection conn) {
        if (conn != null) {
            try { conn.setAutoCommit(false); } catch (Exception ignoreAll) {;} // Do we really need this? hmmm?  jvig
            try { conn.close(); } catch (Throwable ignoreAll) {;}
        }
    }
  
}